#include "modbusmsg.h"

Modbusmsg::Modbusmsg()
{

    readsetings = new QSettings("dataini/Data.ini", QSettings::IniFormat);
    m_thread = new QThread(this);
    this->moveToThread(m_thread);
    readsetings->moveToThread(m_thread);
    m_thread->start();

}
Modbusmsg::~Modbusmsg()
{
    if (m_thread->isRunning())
    {
        m_thread->quit();
        m_thread->wait();
        while (true == m_thread->isRunning());
    }
    readsetings->deleteLater();
    m_thread->deleteLater();
}
//0f 10 功能码请求帧封装开始函数
void Modbusmsg::packageSartc(quint8 addr,quint8 funcode,quint16 startaddr,quint16 num,QByteArray ba,QVector<quint16>regs)
{
    switch(funcode)
    {
    case  15:funCode0f(addr,startaddr,num,ba);
        break;
    case  16:funCode10(addr,startaddr,regs);
        break;
    }
}
//01 03 功能码请求帧封装开始函数
void Modbusmsg::packageSartr(quint8 addr, quint8 funcode, quint16 startaddr, quint16 numreg)
{
    switch(funcode)
    {
    case  1: funCode01(addr,startaddr,numreg);
        break;
    case  3: funCode03(addr,startaddr,numreg);
        break;
    }
}
//01功能码报文封装函数
void Modbusmsg::funCode01(quint8 addr,quint16 startaddr,quint16 numreg)
{
    //从站地址
    msgbuf[0] =addr;
    //功能码
    msgbuf[1] = 0x01;
    //起始地址高位
    msgbuf[2] = startaddr>>8;
    //起始地址低位
    msgbuf[3] = startaddr&0xFF;
    //线圈数量高位
    msgbuf[4] = numreg>>8;
    //线圈数量地位
    msgbuf[5] = numreg&0xFF;
    //CRC校验
    QByteArray crcba((char*)msgbuf,8);
    quint16 crc16 = crc16ForModbus(crcba,CRC_FLAG);
    //CRC校验高位
    msgbuf[6] = crc16>>8;
    //CRC校验低位
    msgbuf[7] = crc16&0xFF;
    QByteArray ba((char*)msgbuf,8);
    requestMessage = ba;
    emit package_over(ba);
    memset(msgbuf,0,8);
}
//03功能码报文封装函数
void Modbusmsg::funCode03(quint8 addr,quint16 startaddr,quint16 numreg)
{
    //从站地址
    msgbuf[0] =addr;
    //功能码
    msgbuf[1] = 0x03;
    //起始地址高位
    msgbuf[2] = startaddr>>8;
    //起始地址低位
    msgbuf[3] = startaddr&0xFF;
    //寄存器数量高位
    msgbuf[4] = numreg>>8;
    //寄存器数量地位
    msgbuf[5] = numreg&0xFF;
    //CRC校验
    QByteArray crcba((char*)msgbuf,8);
    quint16 crc16 = crc16ForModbus(crcba,CRC_FLAG);
    //CRC校验高位
    msgbuf[6] = crc16>>8;
    //CRC校验低位
    msgbuf[7] = crc16&0xFF;
    QByteArray ba((char*)msgbuf,8);
    requestMessage = ba;
    emit package_over(ba);
    memset(msgbuf,0,8);
}
//0f功能码报文封装函数
void Modbusmsg::funCode0f(quint8 addr,quint16 startaddr,quint16 num,QByteArray bas)
{
    quint8 sizenum=bas.size();
    //从站地址
    msgbuf[0] =addr;
    //功能码
    msgbuf[1] = 0x0f;
    //起始地址高位
    msgbuf[2] = startaddr>>8;
    //起始地址低位
    msgbuf[3] = startaddr&0xFF;
    //线圈数量高位
    msgbuf[4] = num>>8;
    //线圈数量地位
    msgbuf[5] = num&0xFF;
    //字节计数
    msgbuf[6] =(quint8)(sizenum);
    //数据
    for(quint16 i=0;i<sizenum;i++)
    {
        msgbuf[7+i] = (quint8)bas.at(i);
    }
    //CRC校验
    QByteArray crcba((char*)msgbuf,9+(quint8)(sizenum));
    quint16 crc16 = crc16ForModbus(crcba,CRC_FLAG);
    //CRC校验高位
    msgbuf[7+sizenum++] = crc16>>8;
    //CRC校验低位
    msgbuf[7+sizenum++] = crc16&0xFF;
    QByteArray ba((char*)msgbuf,7+(quint8)(sizenum));
    requestMessage = ba;
    emit package_over(ba);
    memset(msgbuf,0,7+(quint8)(sizenum));
}
//10功能码报文封装函数
void Modbusmsg::funCode10(quint8 addr,quint16 startaddr,QVector<quint16> addrvalue)
{
    //计算数据大小
    quint16 num= addrvalue.size();
    //从站地址
    msgbuf[0] =addr;
    //功能码
    msgbuf[1] = 0x10;
    //起始地址高位
    msgbuf[2] = startaddr>>8;
    //起始地址低位
    msgbuf[3] = startaddr&0xFF;
    //寄存器数量高位
    msgbuf[4] = num>>8;
    //寄存器数量地位
    msgbuf[5] = num&0xFF;
    //字节计数
    msgbuf[6] =(quint8)(num*2);
    //数据
    for(quint8 k=7,z=0;z<num;z++)
    {
        msgbuf[k++] = (quint16)addrvalue.at(z)>>8;
        msgbuf[k++] = (quint16)addrvalue.at(z)&0xFF;
    }
    //CRC校验
    QByteArray crcba((char*)msgbuf,9+(quint8)(num*2));
    quint16 crc16 = crc16ForModbus(crcba,CRC_FLAG);
    //CRC校验高位
    msgbuf[7+num*2] = crc16>>8;
    //CRC校验低位
    msgbuf[8+num*2] = crc16&0xFF;
    QByteArray ba((char*)msgbuf,9+(quint8)(num*2));
    requestMessage = ba;
    emit package_over(ba);
    memset(msgbuf,0,9+(quint8)(num*2));
    addrvalue.clear();
}
//报文解析
void Modbusmsg::ParseResponseMessage(QByteArray responseMessage)
{
    //RequestMessageArray 接收报文
    QDateTime current_date_time =QDateTime::currentDateTime();
    QString current_date =current_date_time.toString("yyyy.MM.dd hh:mm:ss ddd");
    emit showMsgtoUi(current_date);
    QString s;
    ByteToHexString(s,responseMessage);
    emit showMsgtoUi("响应报文:\n"+s);


    //长度判断：最大长度、最小长度
    if(responseMessage.size() > RTU_MESSAGE_MAX_BYTE)
    {
        emit showlogmsg("/************异常报文************/");
        emit showlogmsg("报文长度错误，超出RTU最大报文长度！");
        return;
    }
    if(responseMessage.size() < ABNORMAL_RESPONSE_LENGTH)
    {
        emit showlogmsg("/************异常报文************/");
        emit showlogmsg("报文长度错误,小于RTU最小报文长度！");
        return;
    }
    //CRC差错校验
    quint16 responseMessageCRC;
    responseMessageCRC = JQChecksum::crc16ForModbus(responseMessage,CRC_FLAG);
    quint16 CrcCheck;
    CrcCheck = BondTwoUint8ToUint16((quint8)responseMessage[responseMessage.size()-2],(quint8)responseMessage[responseMessage.size()-1]);
    if(CrcCheck != responseMessageCRC)
    {
        emit showlogmsg("/************异常报文************/");
        emit showlogmsg("校验码错误，响应报文中校验码错误！");
        return;
    }
    //从机地址是否正确
    if(requestMessage[0] != responseMessage[0])
    {
        emit showlogmsg("/************异常报文************/");
        emit showlogmsg("从机地址错误，响应报文与请求报文的从机地址不一致！");
        return;
    }
    //功能码是否合法
    quint8 responseMessageFuncCode;
    responseMessageFuncCode = (quint8)responseMessage[1];
    switch(responseMessageFuncCode)
    {
    case 0x01:
    case 0x03:
        //QByteArray MessageArr
        RTU0X0103FuncCodeProcess(responseMessage);
        break;
    case 0x0f:
    case 0x10:
        //QByteArray MessageArr
        RTU0X0f10FuncCodeProcess(responseMessage);
        break;
    case 0x81:
    case 0x83:
    case 0x90:
        //QByteArray MessageArr
        RTUExceptionCodeJudge(responseMessage);
        break;
    default:
        emit showlogmsg("/************异常报文************/");
        emit showlogmsg("功能码非法，响应报文中功能码非法！");
        break;
    }
}
//将读取的寄存器数据写入ini文件
void Modbusmsg::WirteRegsDataToIni(quint16 startaddr, quint16 num,QVector<quint16> ba)
{
    for(quint16 i=0,k=startaddr;i<num;i++,k++)
    {
        //写入文件
        QString s = "Section" + QString::number(k+1) + "/regi";
        readsetings->setValue(s,ba.at(i));
    }
}
//将读取的线圈数据写入ini文件
void Modbusmsg::WirteCoilDataToIni(quint16 satrt, QString CoilData)
{
    //更新ini文件数据
    for(int j=0,k=satrt;j<CoilData.length();j++,k++)
    {
        QString s = "Section" + QString::number(k+1) + "/coil";
        quint8 coildata;
        if(CoilData.at(j)=='1')
        {
            coildata = 1;
        }
        else
        {
            coildata = 0;
        }
        readsetings->setValue(s,coildata);
    }
    coildata.clear();
}
//0103报文解析处理
void Modbusmsg::RTU0X0103FuncCodeProcess(QByteArray responseMessage)
{
    if(responseMessage.size()<=5)
    {
        emit showlogmsg("/************异常报文************/");
        emit showlogmsg("查询指令回应报文长度不正确！");
        return;
    }
    //请求与响应的功能码是否一致
    quint8 RequestMessageArrayFuncCode;
    RequestMessageArrayFuncCode = (quint8)requestMessage[1];
    if(RequestMessageArrayFuncCode != responseMessage.at(1))
    {
        emit showlogmsg("/************异常报文************/");
        emit showlogmsg("功能码错误，响应报文与请求报文中的功能码不一致！");
        return;
    }
    //0x01 0x03
    //正常报文响应长度 1+1+1+n+2
    //响应报文中 数据域字节数 与 实际数据所用字节总数 是否一致
    quint8 responseMessageDataNumber;
    responseMessageDataNumber = responseMessage.size() - 5;
    if((quint8)responseMessage[2] != responseMessageDataNumber)
    {
        emit showlogmsg("/************异常报文************/");
        emit showlogmsg("字节数错误，响应报文中数据域字节数和实际数据字节总数不一致！");
        return;
    }
    //处理匹配的正常响应码
    QString dataObtained;
    quint16 startaddr = BondTwoUint8ToUint16(requestMessage.at(2),requestMessage.at(3));
    quint16 num = BondTwoUint8ToUint16(requestMessage.at(4),requestMessage.at(5));
    if(responseMessage.at(1)==1)
    {
        //取出所读的多个线圈，并显示，数据从第九位开始
        for(int i = 0; i < (quint8)responseMessage.at(2); i++)
        {
            //先转化为2进制字符串
            QString str = QString::number((quint8)responseMessage.at(3 + i),2);
            //再转化为2进制整形，由二进制整形转化为8位2进制字符串前面自动补0，从而保证8位
            str = QString("%1").arg((quint8)str.toInt(NULL,2),8,2,QChar('0'));
            //8bit字节倒转
            byteReverse(str);
            //添加到数据中
            dataObtained += str;
            coildata +=str;
        }
        emit wirtTablec(num,startaddr,dataObtained);
        //去除填充的0位，读出请求报文请求的线圈数
        dataObtained = dataObtained.left(num);
        //提示响应报文解析成功
        //消息窗口显示信息
        emit showlogmsg("多线圈读取成功!");
        emit showlogmsg(dataObtained);
        WirteCoilDataToIni(startaddr,coildata);
    }
    else if(responseMessage.at(1)==3)
    {
        //取出所读的多个寄存器，并显示，数据从第9个字节开始
        for(int i = 0;i < (quint8)responseMessage.at(2); i += 2)
        {
            dataObtained += QString::number(BondTwoUint8ToUint16((quint8)responseMessage.at(3 + i),(quint8)responseMessage.at(4 + i)));
            bar.push_back(BondTwoUint8ToUint16((quint8)responseMessage.at(3 + i),(quint8)responseMessage.at(4 + i)));
            dataObtained += " ";
        }
        emit wirtTabler(num,startaddr,bar);
        //消息窗口显示信息
        emit showlogmsg("多寄存器读取成功!");
        emit showlogmsg(dataObtained);
        WirteRegsDataToIni(startaddr,num,bar);
    }
}
//0f10报文解析处理
void Modbusmsg::RTU0X0f10FuncCodeProcess(QByteArray responseMessage)
{
    if(responseMessage.size()<WRITE_RESPONSE_LENGTH)
    {
        emit showlogmsg("/************异常报文************/");
        emit showlogmsg("写指令回应报文长度错误！");
    }
    //请求与响应的功能码是否一致
    quint8 RequestMessageArrayFuncCode;
    RequestMessageArrayFuncCode = (quint8)requestMessage[1];
    if(RequestMessageArrayFuncCode != responseMessage.at(1))
    {
        emit showlogmsg("/************异常报文************/");
        emit showlogmsg("功能码错误，响应报文与请求报文中的功能码不一致！");
        return;
    }
    //0x0f 0x10
    //正常响应正常长度8  1+1+2+2+2
    //起始地址是否一致
    quint16 responseMessageBeginAddress;
    responseMessageBeginAddress=BondTwoUint8ToUint16((quint8)responseMessage[2],(quint8)responseMessage[3]);
    quint16 RequestMessageArrayBeginAddress;
    RequestMessageArrayBeginAddress=BondTwoUint8ToUint16((quint8)requestMessage[2],(quint8)requestMessage[3]);
    if(responseMessageBeginAddress != RequestMessageArrayBeginAddress)
    {
        emit showlogmsg("/************异常报文************/");
        emit showlogmsg("起始地址错误，响应报文中起始地址与请求报文的不一致！");
        return;
    }
    //查询数量是否一致
    quint16 responseMessageNumber;
    responseMessageNumber=BondTwoUint8ToUint16((quint8)responseMessage[4],(quint8)responseMessage[5]);
    quint16 RequestMessageArrayNumber;
    RequestMessageArrayNumber=BondTwoUint8ToUint16((quint8)requestMessage[4],(quint8)requestMessage[5]);
    if(responseMessageNumber != RequestMessageArrayNumber)
    {
        emit showlogmsg("/************异常报文************/");
        emit showlogmsg("数量错误，响应报文中写入数据数量与请求报文的不一致！");
        return;
    }
}
//异常功能码处理
void Modbusmsg::RTUExceptionCodeJudge(QByteArray responseMessage)
{
    if(responseMessage.size()!=5)
    {
        emit showlogmsg("/************异常报文************/");
        emit showlogmsg("01，02，03异常回应报文长度不正确！");
        return;
    }
    QString exceptionCodePrompt;
    quint8 excCode = (quint8)responseMessage.at(2);
    switch (excCode)
    {
    case 0x01:
    {
        exceptionCodePrompt = "异常码为：01 非法功能";
        break;
    }
    case 0x02:
    {
        exceptionCodePrompt = "异常码为：02 非法数据地址";
        break;
    }
    case 0x03:
    {
        exceptionCodePrompt = "异常码为：03 非法数据值";
        break;
    }
    }
    //消息窗口显示信息
    emit showlogmsg(exceptionCodePrompt);
    return;
}
